package com.demo.function.spring.resolver;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.core.MethodParameter;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver;
import org.springframework.web.method.annotation.RequestHeaderMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;

import javax.annotation.Resource;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 请求头参数值转换成对象
 * @author cyj
 */
@Slf4j
@Component
public class ReplaceRequestHeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver implements InitializingBean {

    @Resource
    private RequestMappingHandlerAdapter requestMappingHandlerAdapter;

    @Resource
    private DefaultListableBeanFactory defaultListableBeanFactory;

    public ReplaceRequestHeaderMethodArgumentResolver(ConfigurableBeanFactory beanFactory) {
        super(beanFactory);
    }

    @Override
    @NonNull
    protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
        RequestHeader ann = parameter.getParameterAnnotation(RequestHeader.class);
        Assert.state(ann != null, "No RequestHeader annotation");
        return new ReplaceRequestHeaderMethodArgumentResolver.RequestHeaderNamedValueInfo(ann);
    }

    @Override
    protected Object resolveName(@NonNull String name, @NonNull MethodParameter parameter, NativeWebRequest request) {
        String[] headerValues = request.getHeaderValues(name);
        if (headerValues == null){
            return null;
        }

        if (parameter.getParameterType() != String.class){
            String objStr = headerValues[0];
            log.info("请求头value:{}", objStr);
            if (StringUtils.isEmpty(objStr)){
                return null;
            }
            String decode = URLDecoder.decode(objStr, StandardCharsets.UTF_8);
            return JSON.parseObject(decode,parameter.getParameterType());
        }

        return (headerValues.length == 1 ? headerValues[0] : headerValues);
    }

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return (parameter.hasParameterAnnotation(RequestHeader.class) &&
                !Map.class.isAssignableFrom(parameter.nestedIfOptional().getNestedParameterType()));
    }

    @Override
    public void afterPropertiesSet() {
        List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(ObjectUtils.defaultIfNull(requestMappingHandlerAdapter.getArgumentResolvers(), Lists.newArrayList()));
        for (int i=0;i<resolvers.size();i++){
            if (resolvers.get(i) instanceof RequestHeaderMethodArgumentResolver){
                resolvers.set(i,new ReplaceRequestHeaderMethodArgumentResolver(defaultListableBeanFactory));
            }
        }
        requestMappingHandlerAdapter.setArgumentResolvers(resolvers);
    }

    private static final class RequestHeaderNamedValueInfo extends NamedValueInfo {

        private RequestHeaderNamedValueInfo(RequestHeader annotation) {
            super(annotation.name(), annotation.required(), annotation.defaultValue());
        }
    }
}
